iT邦幫忙

2024 iThome 鐵人賽

DAY 2
0
佛心分享-SideProject30

RISC-V CPU 設計與實作系列 第 6

[Day 06] Simulation with Icarus Verilog

  • 分享至 

  • xImage
  •  

前面的篇幅大致說明了基本的 Verilog 語法,如果想要認識更多內容可以參考筆者寫的 數位IC起手式 ,裡面記載我在學習 Verilog 的學習過程和思路,相信可以幫到你們!

檢測電路正確性

當我們設計了一個電路,我們要檢測這個電路的邏輯是否正確。測試的方式有兩種,第一種是透過模擬器生成波形圖檔案,再透過波形圖檢查電路運作過程是否正確,第二種是將電路燒錄到 FPGA 中,使用真的硬體來去檢測電路運作。

使用 FPGA 固然可以更準確的檢測電路,但是這個板子並不便宜,也不是隨手可得的資源,因此使用波形圖模擬 (simulation) 電路,在電路設計中扮演很重要的角色。

在這一篇文章中,我們會學著怎麼使用 Icarus Verilog (簡稱 Iverilog) 搭配 GTKWave 來模擬並檢測電路。其中,Iverilog 是一套模擬器,透過這個工具,我們可以把 Verilog 轉換成特定格式,並模擬電路。通常我們會再把相關資料輸出成波形圖格式 (.vcd) ,並用 GTKWave 開啟。

Testbench

假設我們設計了一個加法器,程式碼如下:

module FullAdder(
    output Cout, Sum,
    input A, B, Cin
);
    assign Cout = (A & B) | (B & Cin) | (A & Cin);
    assign Sum = A ^ B ^ Cin;
endmodule

為了要檢查電路是否正確,我們要設計一個測試檔案(testbench) ,這個檔案說明了測資該怎麼被傳入模組,還有我們傳入了哪些側資。除此之外,我們也可以在其中加上「輸出成波形圖」的相關敘述,如此就可以更直覺地看出電路的運作過程。

module tb;
    wire Cout, Sum;
    reg A, B, Cin;
    
    FullAdder FA(Cout, Sum, A, B, Cin);
    
    initial begin
        $dumpfile("FAdder.vcd");
        $dumpvars(0, tb);
    end
    
    initial begin
        A = 1'b1; B = 1'b1; Cin = 1'b1; 
        #2
        A = 1'b0; B = 1'b1; Cin = 1'b1; 
        #2
        A = 1'b1; B = 1'b0; Cin = 1'b0; 
        #2
        A = 1'b0; B = 1'b1; Cin = 1'b0; 
        #2
        $finish();
    end
endmodule

說明上述的語法:

  1. 輸出「波形圖」檔案:這段敘述可以當作公式使用,特別注意的是 FAdder.vcd 代表波形圖的檔案名稱,可以根據自己的需求更改檔名。另一個要注意的是 tb 代表 testbench 的模組名稱 (module name) ,因此這需要根據當前情況作更動。
initial begin
    $dumpfile("FAdder.vcd");
    $dumpvars(0, tb);
end
  1. 連接「欲測試模組」的線路:變數名稱不用和「欲測試模組」的接口名稱相同,不過要特別注意的是若這個變數連接的是輸入端,則使用 reg ,否則使用 wire 。因為我們會不斷的更動輸入資料,所以輸入端的接口需要設定為 reg,也就是暫存器。
wire Cout, Sum;
reg A, B, Cin;
  1. 延遲(#n):延遲僅僅是讓我們看波形圖時,能清楚知道各個時間段的電路表現為何。若不加上延遲,電路運作的速度極快,波形圖完全無法表現出來。延遲通常加在兩組測資之間。

模擬

使用 Iverilog 模擬我們需要下達兩組指令。

  1. 產生模擬用檔案:(FAdder, tb_FAdder.v 需根據自己的情況更改)
iverilog -o FAdder tb_FAdder.v
  1. 執行模擬的檔案:(FAdder 為上述產生的檔案)
vvp FAdder
  1. 打開波形圖:(GTKWave 可以透過 GUI 介面打開,並開啟 testbench 產生的 FAdder.vcd)
gtkwave FAdder.vcd

波形圖結果如下圖:
https://ithelp.ithome.com.tw/upload/images/20240706/20150982vInuj85vUl.png

後記

到這邊就是完整的模擬過程,當然大家也可以使用 $display() 輸出某個變數在不同時間的數值,過程大致上就和在 C 程式設計時,使用 printf() 輸出目標變數相同。差別在於 $display() 要放在 always 或是 initial 中,也因為這是電路設計,因此 $display() 被呼叫的次數可能大於一遍,畢竟電路是不間斷的。


上一篇
[Day 05] Blocking & Nonblocking
系列文
RISC-V CPU 設計與實作6
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言